#include "SW_CRC.h"

uint8_t SW_CRC8_Calculate(SW_CRC8_st_t *stType, uint8_t u8Data[], uint32_t u32Len)
{
	uint8_t value = stType->u8InitVal;

	if (stType->u8RefIn) /**逆序 LSB 输入*/ 
	{
		value = reflected(stType->u8InitVal, 8U);
	}

	while (u32Len--)
	{
		value = stType->pu8Table[value ^ *u8Data++];		/**根据当前 CRC 值和数据字节计算新的 CRC 值*/
	}

	/**逆序输出*/ 
	if (stType->u8RefOut != stType->u8RefIn)
		value = reflected(value, 8U);

	/**异或输出*/ 
	value ^= stType->u8XorOut;

	return value;
}


/**************************************************************************************
 * @brief     【软件CRC16位计算】
 * @param[in] stType【计算CRC所需参数 - 详见 SW_CRC16_st_t 】
 * @param[in] u8Data【所计算数据】
 * @param[in] u32Len【数据长度】
 * @return    uint16_t 【返回计算CRC结果】
 * 
 * @note 1．设置CRC寄存器，并给其赋值初始值(hex)。
 * @note 2．将数据的第一个8-bit字符与16位CRC寄存器的低8位进行异或，并把结果存入CRC寄存器。
 * @note 3．CRC寄存器向右移一位，MSB补零，移出并检查LSB。
 * @note 4．如果LSB为0，重复第三步；若LSB为1，CRC寄存器与多项式码相异或。
 * @note 5．重复第3与第4步直到8次移位全部完成。此时一个8-bit数据处理完毕。
 * @note 6．重复第2至第5步直到所有数据全部处理完成。
 * @note 7．最终CRC寄存器的内容即为CRC值。
 * 
 * @since     1.0.0
 **************************************************************************************/
uint16_t SW_CRC16_Calculate(SW_CRC16_st_t *stType, uint8_t u8Data[], uint32_t u32Len)
{
	uint8_t u8high;
	uint16_t u16value = stType->u16InitVal;

	/**逐字节循环遍历数据，并使用查表法计算新的 CRC 值。*/
	/**查表索引是当前 CRC 值的高 8 位与当前数据字节的异或值*/
	if (stType->u8RefIn) // 逆序 LSB 输入
	{
		u16value = reflected(stType->u16InitVal, 16U);
		while (u32Len--)
		{
			u16value = (u16value >> 8) ^ stType->pu16Table[(u16value & 0xff) ^ *u8Data++];		/**根据当前 CRC 值和数据字节计算新的 CRC 值*/
		}
	}
	else // 正序 MSB 输入
	{
		while (u32Len--)
		{
			u8high = u16value >> (16 - 8);
			u16value = (u16value << 8) ^ stType->pu16Table[u8high ^ *u8Data++];
		}
	}

	// 逆序输出
	if (stType->u8RefOut != stType->u8RefIn)
		u16value = reflected(u16value, 16U);

	// 异或输出
	u16value ^= stType->u16XorOut;

	return u16value & 0xFFFFU;
}

uint32_t SW_CRC32_Calculate(SW_CRC32_st_t *stType, uint8_t u8Data[], uint32_t u32Len)
{
	uint8_t u8high;
	uint32_t u32value = stType->u32InitVal;

	if (stType->u8RefIn) // 逆序 LSB 输入
	{
		u32value = reflected(stType->u32InitVal, 32U);
		while (u32Len--)
		{
			u32value = (u32value >> 8) ^ stType->pu32Table[(u32value & 0xff) ^ *u8Data++];		/**根据当前 CRC 值和数据字节计算新的 CRC 值*/
		}
	}
	else // 正序 MSB 输入
	{
		while (u32Len--)
		{
			u8high = u32value >> (32 - 8);		/**将 32 位 CRC 值 u32value 右移 24 位，提取最高字节。这相当于将 CRC 值除以 256，只保留余数*/
			u32value = (u32value << 8) ^ stType->pu32Table[u8high ^ *u8Data++];
		}
	}

	// 逆序输出
	if (stType->u8RefOut != stType->u8RefIn)
		u32value = reflected(u32value, 32U);

	// 异或输出
	u32value ^= stType->u32XorOut;

	return u32value & 0xFFFFFFFFU;
}
